﻿#region using
using System;
using Microsoft.JScript.Vsa;
using Microsoft.JScript;
using System.Reflection;
using System.Reflection.Emit;
using System.IO;
using System.Diagnostics.SymbolStore;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Jsil.Runtime;
using System.Text.RegularExpressions;
using System.Diagnostics;
#endregion using

namespace Jsil.Compiler
{
	public enum RuntimeMethodsUsage { Call, Copy };
	public enum LocalsGeneration { Field, Local };
	public enum FileKind { Dll, Exe };
	public static class MpJScriptCompiler
	{
		#region public
#pragma warning disable 0618
		static VsaEngine _engine;
#pragma warning disable 0618
		static ConstructorInfo _documentContextCi;
		static ConstructorInfo _contextCi;

		static MpJScriptCompiler()
		{
#pragma warning disable 0618
			_engine=VsaEngine.CreateEngine();
			_documentContextCi=typeof(DocumentContext).GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance,null,new Type[] { typeof(string),typeof(VsaEngine) },null);
#pragma warning disable 0618
			_contextCi=typeof(Context).GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance,null,new Type[] { typeof(DocumentContext),typeof(string) },null);
		}

		public static void Compile(string code,string filename,CompilerOptions options)
		{
			Dictionary<string,string> predefinedImports;
			Preprocess(ref code,out predefinedImports);

			Context context=(Context)_contextCi.Invoke(new object[] { _documentContextCi.Invoke(new object[] { "script",_engine }),code });
			JSParser jSParser=new JSParser(context);
			ScriptBlock block;
			lock (_engine)
				block=jSParser.Parse();

			new Compiler().Compile(block,filename,options,predefinedImports);
		}

		#region Preprocess
		static Regex _importRegex=new Regex(@"import\s(?<libName>[^=]*)\s*=\s*(?<path>[^;]*);",RegexOptions.Compiled);
		static Regex _fullCommentRegex=new Regex(@"(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)",RegexOptions.Compiled);
		static Regex _lineCommentRegex=new Regex(@"//.*?$",RegexOptions.Compiled|RegexOptions.Multiline);
		static void Preprocess(ref string code,out Dictionary<string,string> predefinedImports)
		{
			List<Interval> commentRegions=new List<Interval>();
			PreprocessRemoveComments(code,_fullCommentRegex,commentRegions);
			PreprocessRemoveComments(code,_lineCommentRegex,commentRegions);
		
			MatchCollection matches=_importRegex.Matches(code);
			int matchesCount=matches.Count;
			predefinedImports=new Dictionary<string,string>(matchesCount);
			if (matchesCount==0)
				return;

			StringBuilder sb=new StringBuilder(code);
			for (int a=matchesCount-1;a>=0;a--)
			{
				Group libNameGr=matches[a].Groups["libName"];
				Group pathGr=matches[a].Groups["path"];
				int posStart=libNameGr.Index+libNameGr.Length;
				int posEnd=pathGr.Index+pathGr.Length;
				
				bool continuee=false;
				foreach (Interval item in commentRegions)
					if (item.Crosses(posStart,posEnd))
					{
						continuee=true;
						break;
					}
				if (continuee)
					continue;

				predefinedImports.Add(libNameGr.Value,pathGr.Value);
				sb.Insert(posEnd," */");
				sb.Insert(posStart,"/* ");
			}
			code=sb.ToString();
		}

		static void PreprocessRemoveComments(string code,Regex commentMatches,List<Interval> commentRegions)
		{
			MatchCollection matches=commentMatches.Matches(code);
			foreach (Match item in matches)
			{
				int start=item.Index;
				commentRegions.Add(new Interval(){Start=start,End=item.Length+start});
			}
		}
		
		class Interval
		{
			internal int Start;
			internal int End;
			
			internal bool Crosses(int otherStart,int otherEnd)
			{
				return (otherStart<End)&&(otherEnd>Start);
			}
		}
		#endregion Preprocess
		#endregion public

		class Compiler
		{
			#region fields
			ModuleBuilder _modBldr;
			TypeBuilder _typBldr,_myTypeBldr;
			ISymbolDocumentWriter _symbolWriter;
			static Type _objectType=typeof(object);
			bool _debug;
			RuntimeMethodsUsage _runtimeMethodsUsage;
			LocalsGeneration _localsGeneration;
			RuntimeCopier _typeCopier;
			Stack<FunctionInfo> _functions=new Stack<FunctionInfo>();
			List<TypeBuilder> _createdFunctions=new List<TypeBuilder>();
			List<string> _externalLibs=new List<string>();
			Point _lastPoint;
			#endregion fields

			#region Compile
			internal void Compile(ScriptBlock code,string filename,CompilerOptions options,Dictionary<string,string> predefinedImports)
			{
				_debug=options.Debug;
				_runtimeMethodsUsage=options.RuntimeMethodsUsage;
				_localsGeneration=LocalsGeneration.Field/*options.LocalsGeneration*/;
				string sourceFilename=options.SourceFilename;

				string f=Path.GetFileName(filename);
				string p=Path.GetDirectoryName(filename);
				string fwe=Path.GetFileNameWithoutExtension(f);
				string srcPath=null;
				AssemblyName asmName=new AssemblyName(fwe);
				AssemblyBuilder asmBldr=AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,AssemblyBuilderAccess.Save,p);
				_modBldr=asmBldr.DefineDynamicModule(f,f,_debug);
				if (_debug)
				{
					asmBldr.SetCustomAttribute(new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool),typeof(bool) }),new object[] { true,true }));
					srcPath=sourceFilename.Length==0?Path.Combine(p,fwe)+".js":sourceFilename;
					_symbolWriter=_modBldr.DefineDocument(srcPath,SymDocumentType.Text,SymLanguageType.JScript,Guid.Empty);
				}
				if (_runtimeMethodsUsage==RuntimeMethodsUsage.Copy)
				{
					_typeCopier=new RuntimeCopier(typeof(Jsil.Runtime.GlobalObject).Assembly,_modBldr);
					_typeCopier.Copy();
				}
				_myTypeBldr=_modBldr.DefineType("MyType",TypeAttributes.BeforeFieldInit|TypeAttributes.Sealed|TypeAttributes.Public,GetRuntimeType(typeof(Jsil.Runtime.MainFunctionObject)));
				_typBldr=_myTypeBldr;
				CreateRuntimeInfo();

				ScriptBlockWrapper sbw=new ScriptBlockWrapper(code);
				MethodBuilder m=_typBldr.DefineMethod("Main",MethodAttributes.Public,typeof(void),new Type[0]);
				ILGenerator gen=m.GetILGenerator();
				_functions.Push(new FunctionInfo());
				GenerateNode(gen,sbw.Statement);
				FinalizeFunctionPushes(gen);
				if (_debug)
					if (_lastPoint==null)
						gen.MarkSequencePoint(_symbolWriter,1,1,1,1);
					else
						gen.MarkSequencePoint(_symbolWriter,_lastPoint.EndLine,_lastPoint.EndColumn+2,_lastPoint.EndLine,_lastPoint.EndColumn+2);
				gen.Emit(OpCodes.Ret);

				ConstructorBuilder cb=_typBldr.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,Type.EmptyTypes);
				CallResolvePredefinedImports(cb,predefinedImports);
				DefineVariables(cb,_functions.Peek());
				DefineExternalVariables(cb,_functions.Peek());
				cb.GetILGenerator().Emit(OpCodes.Ret);

				TypeBuilder[] funcs=_createdFunctions.ToArray();
				Array.Reverse(funcs);
				foreach (TypeBuilder item in funcs)
					item.CreateType();

				if (options.FileKind==FileKind.Exe)
					GenerateStaticExecutor(asmBldr,_typBldr);

				_typBldr.CreateType();
				asmBldr.Save(f,PortableExecutableKinds.ILOnly,ImageFileMachine.I386);
				if ((_debug)&&(sourceFilename.Length==0))
					using (StreamWriter sw=File.CreateText(srcPath))
						sw.Write(sbw.Context.GetCode());
			}

			void CreateRuntimeInfo()
			{
				Assembly asm=typeof(Jsil.Runtime.GlobalObject).Assembly;
				TypeBuilder typBldr=_modBldr.DefineType("CompileRuntimeInfo",TypeAttributes.BeforeFieldInit|TypeAttributes.Sealed|TypeAttributes.Public,_objectType);
				FieldBuilder fb=typBldr.DefineField("Version",typeof(string),FieldAttributes.Public|FieldAttributes.Literal|FieldAttributes.HasDefault);
				fb.SetConstant(asm.GetName().Version.ToString());
				fb=typBldr.DefineField("ModuleVersionId",typeof(string),FieldAttributes.Public|FieldAttributes.Literal|FieldAttributes.HasDefault);
				fb.SetConstant(asm.ManifestModule.ModuleVersionId.ToString());
				fb=typBldr.DefineField("RuntimeCopied",typeof(bool),FieldAttributes.Public|FieldAttributes.Literal|FieldAttributes.HasDefault);
				fb.SetConstant(_runtimeMethodsUsage==RuntimeMethodsUsage.Copy);
				typBldr.CreateType();
			}

			void CallResolvePredefinedImports(ConstructorBuilder cb,Dictionary<string,string> predefinedImports)
			{
				ILGenerator gen=cb.GetILGenerator();
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Call,GetRuntimeConstructor(typeof(MainFunctionObject).GetConstructor(Type.EmptyTypes)));

				FieldInfo fi=GetRuntimeField(typeof(Jsil.Runtime.GlobalObject).GetField("_predefinedImports",BindingFlags.NonPublic|BindingFlags.Instance));
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Ldc_I4,predefinedImports.Count);
				gen.Emit(OpCodes.Newobj,typeof(Dictionary<string,string>).GetConstructor(new Type[] { typeof(int) }));
				gen.Emit(OpCodes.Stfld,fi);

				foreach (KeyValuePair<string,string> item in predefinedImports)
				{
					gen.Emit(OpCodes.Ldarg_0);
					gen.Emit(OpCodes.Ldfld,fi);
					gen.Emit(OpCodes.Ldstr,item.Key);
					gen.Emit(OpCodes.Ldstr,item.Value);
					gen.Emit(OpCodes.Callvirt,typeof(IDictionary<string,string>).GetMethod("Add"));
				}
			}

			void DefineVariables(ConstructorBuilder cb,FunctionInfo fi)
			{
				SortedDictionary<string,object> variables=fi.Variables;

				ILGenerator gen=cb.GetILGenerator();
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Ldc_I4,variables.Count);
				gen.Emit(OpCodes.Newarr,typeof(string));

				int a=0;
				foreach (KeyValuePair<string,object> item in variables)
				{
					gen.Emit(OpCodes.Dup);
					gen.Emit(OpCodes.Ldc_I4,a++);
					gen.Emit(OpCodes.Ldstr,item.Key);
					gen.Emit(OpCodes.Stelem_Ref);
				}

				gen.Emit(OpCodes.Stfld,GetRuntimeField(typeof(FunctionObjectBase).GetField("_definedVariables",BindingFlags.NonPublic|BindingFlags.Instance)));
			}

			void DefineExternalVariables(ConstructorBuilder cb,FunctionInfo fi)
			{
				List<string> variables=fi.ExternalVariables;
				variables.Sort(FunctionObjectBase.VariableNameComparer);

				ILGenerator gen=cb.GetILGenerator();
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Ldc_I4,variables.Count);
				gen.Emit(OpCodes.Newarr,typeof(string));

				int a=0;
				foreach (string item in variables)
				{
					gen.Emit(OpCodes.Dup);
					gen.Emit(OpCodes.Ldc_I4,a++);
					gen.Emit(OpCodes.Ldstr,item);
					gen.Emit(OpCodes.Stelem_Ref);
				}

				gen.Emit(OpCodes.Stfld,GetRuntimeField(typeof(FunctionObjectBase).GetField("_definedExternalVariables",BindingFlags.NonPublic|BindingFlags.Instance)));
			}

			void GenerateStaticExecutor(AssemblyBuilder asmBldr,TypeBuilder typBldr)
			{
				MethodBuilder m=typBldr.DefineMethod("~~Run",MethodAttributes.Public|MethodAttributes.Static,typeof(void),new Type[] { typeof(string[]) });
				ILGenerator gen=m.GetILGenerator();
				if (_debug)
					gen.MarkSequencePoint(_symbolWriter,1,1,1,1);
				gen.Emit(OpCodes.Call,typeof(Assembly).GetMethod("GetExecutingAssembly",BindingFlags.Public|BindingFlags.Static));
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Call,GetRuntimeMethod(typeof(Executor).GetMethod("RunExe",BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static,null,new Type[] { typeof(Assembly),typeof(string[]) },null)));
				gen.Emit(OpCodes.Ret);
				asmBldr.SetEntryPoint(m,PEFileKinds.ConsoleApplication);
			}
			#endregion Compile

			#region generate methods
			#region GenerateNode/root
			List<AST> _nodeStack=new List<AST>();
			int _nodeStackLevel=-1;
			void GenerateNode(ILGenerator gen,AST node)
			{
				Point point=new Point(node);
				if ((_lastPoint==null)||(point.CompareTo(_lastPoint)==1))
					_lastPoint=point;
				if ((!LookupWrapper.CheckType(node))&&(!ConstantWrapperWrapper.CheckType(node)))
					MarkSequencePoint(gen,node);
				_nodeStackLevel++;
				if (_nodeStack.Count<=_nodeStackLevel)
					_nodeStack.Insert(_nodeStackLevel,node);
				else
					_nodeStack[_nodeStackLevel]=node;

				/*if (AddressOfWrapper.CheckType(node))
					GenerateAddressOf(gen,node);
				else if (DeleteWrapper.CheckType(node))
					GenerateDelete(gen,node);
				else */
				if (NumericUnaryWrapper.CheckType(node))
					GenerateNumericUnary(gen,node);
				else if (PostOrPrefixOperatorWrapper.CheckType(node))
					GeneratePostOrPrefixOperator(gen,node);
				/*else if (TypeofWrapper.CheckType(node))
					GenerateTypeof(gen,node);
				else if (VoidOpWrapper.CheckType(node))
					GenerateVoidOp(gen,node);
				else if (UnaryOpWrapper.CheckType(node))
					GenerateUnaryOp(gen,node);*/
				else if (ArrayLiteralWrapper.CheckType(node))
					GenerateArrayLiteral(gen,node);
				/*else if (AssemblyCustomAttributeListWrapper.CheckType(node))
					GenerateAssemblyCustomAttributeList(gen,node);*/
				else if (ASTListWrapper.CheckType(node))
					GenerateASTList(gen,node);
				else if (BitwiseBinaryWrapper.CheckType(node))
					GenerateBitwiseBinary(gen,node);
				/*else if (BitwiseBinaryAssignWrapper.CheckType(node))
					GenerateBitwiseBinaryAssign(gen,node);*/
				else if (EqualityWrapper.CheckType(node))
					GenerateEquality(gen,node);
				/*else if (InWrapper.CheckType(node))
					GenerateIn(gen,node);
				else if (InstanceofWrapper.CheckType(node))
					GenerateInstanceof(gen,node);*/
				else if (Logical_andWrapper.CheckType(node))
					GenerateLogical_and(gen,node);
				else if (Logical_orWrapper.CheckType(node))
					GenerateLogical_or(gen,node);
				else if (PlusWrapper.CheckType(node))
					GeneratePlus(gen,node);
				else if (PlusAssignWrapper.CheckType(node))
					GeneratePlusAssign(gen,node);
				/*else if (CommaWrapper.CheckType(node))
					GenerateComma(gen,node);*/
				else if (NumericBinaryWrapper.CheckType(node))
					GenerateNumericBinary(gen,node);
				/*else if (NumericBinaryAssignWrapper.CheckType(node))
					GenerateNumericBinaryAssign(gen,node);*/
				else if (RelationalWrapper.CheckType(node))
					GenerateRelational(gen,node);
				/*else if (StrictEqualityWrapper.CheckType(node))
					GenerateStrictEquality(gen,node);
				else if (BinaryOpWrapper.CheckType(node))
					GenerateBinaryOp(gen,node);
				else if (CallableExpressionWrapper.CheckType(node))
					GenerateCallableExpression(gen,node);*/
				else if (LookupWrapper.CheckType(node))
					GenerateLookup(gen,node);
				else if (MemberWrapper.CheckType(node))
					GenerateMember(gen,node);
				/*else if (BindingWrapper.CheckType(node))
					GenerateBinding(gen,node);*/
				else if (BlockWrapper.CheckType(node))
					GenerateBlock(gen,node);
				/*else if (EmptyLiteralWrapper.CheckType(node))
					GenerateEmptyLiteral(gen,node);*/
				else if (NullLiteralWrapper.CheckType(node))
					GenerateNullLiteral(gen,node);
				else if (ConstantWrapperWrapper.CheckType(node))
					GenerateConstantWrapper(gen,node);
				/*else if (ConstructorCallWrapper.CheckType(node))
					GenerateConstructorCall(gen,node);
				else if (CustomAttributeListWrapper.CheckType(node))
					GenerateCustomAttributeList(gen,node);*/
				else if (DebugBreakWrapper.CheckType(node))
					GenerateDebugBreak(gen,node);
				/*else if (EvalWrapper.CheckType(node))
					GenerateEval(gen,node);
				else if (ForInWrapper.CheckType(node))
					GenerateForIn(gen,node);*/
				else if (FunctionDeclarationWrapper.CheckType(node))
					GenerateFunctionDeclaration(gen,node);
				else if (FunctionExpressionWrapper.CheckType(node))
					GenerateFunctionExpression(gen,node);
				else if (ImportWrapper.CheckType(node))
					GenerateImport(gen,node);
				/*else if (PackageWrapper.CheckType(node))
					GeneratePackage(gen,node);
				else if (ScriptBlockWrapper.CheckType(node))
					GenerateScriptBlock(gen,node);*/
				else if (ThrowWrapper.CheckType(node))
					GenerateThrow(gen,node);
				else if (TryWrapper.CheckType(node))
					GenerateTry(gen,node);
				/*else if (TypeExpressionWrapper.CheckType(node))
					GenerateTypeExpression(gen,node);
				else if (WithWrapper.CheckType(node))
					GenerateWith(gen,node);*/
				else if (AssignWrapper.CheckType(node))
					GenerateAssign(gen,node);
				else if (BreakWrapper.CheckType(node))
					GenerateBreak(gen,node);
				else if (CallWrapper.CheckType(node))
					GenerateCall(gen,node);
				/*else if (EnumDeclarationWrapper.CheckType(node))
					GenerateEnumDeclaration(gen,node);
				else if (ClassWrapper.CheckType(node))
					GenerateClass(gen,node);*/
				else if (ConditionalWrapper.CheckType(node))
					GenerateConditional(gen,node);
				/*else if (ConstantWrapper.CheckType(node))
					GenerateConstant(gen,node);*/
				else if (ContinueWrapper.CheckType(node))
					GenerateContinue(gen,node);
				/*else if (CustomAttributeWrapper.CheckType(node))
					GenerateCustomAttribute(gen,node);
				else if (DoWhileWrapper.CheckType(node))
					GenerateDoWhile(gen,node);*/
				else if (ExpressionWrapper.CheckType(node))
					GenerateExpression(gen,node);
				else if (ForWrapper.CheckType(node))
					GenerateFor(gen,node);
				/*else if (IdentifierLiteralWrapper.CheckType(node))
					GenerateIdentifierLiteral(gen,node);*/
				else if (IfWrapper.CheckType(node))
					GenerateIf(gen,node);
				else if (ObjectLiteralWrapper.CheckType(node))
					GenerateObjectLiteral(gen,node);
				/*else if (PrintWrapper.CheckType(node))
					GeneratePrint(gen,node);*/
				else if (RegExpLiteralWrapper.CheckType(node))
					GenerateRegExpLiteral(gen,node);
				else if (ReturnWrapper.CheckType(node))
					GenerateReturn(gen,node);
				/*else if (StaticInitializerWrapper.CheckType(node))
					GenerateStaticInitializer(gen,node);*/
				else if (SwitchWrapper.CheckType(node))
					GenerateSwitch(gen,node);
				/*else if (SwitchCaseWrapper.CheckType(node))
					GenerateSwitchCase(gen,node);*/
				else if (ThisLiteralWrapper.CheckType(node))
					GenerateThisLiteral(gen,node);
				else if (VariableDeclarationWrapper.CheckType(node))
					GenerateVariableDeclaration(gen,node);
				else if (WhileWrapper.CheckType(node))
					GenerateWhile(gen,node);
				else
					throw new NotImplementedException();

				_nodeStackLevel--;
			}
			#endregion GenerateNode/root

			/*void GenerateUnaryOp(ILGenerator gen,AST node)
			{
				UnaryOpWrapper w=new UnaryOpWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateAddressOf(ILGenerator gen,AST node)
			{
				AddressOfWrapper w=new AddressOfWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateDelete(ILGenerator gen,AST node)
			{
				DeleteWrapper w=new DeleteWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateNumericUnary(ILGenerator gen,AST node)
			{
				NumericUnaryWrapper w=new NumericUnaryWrapper(node);

				switch (w.OperatorTok)
				{
					case JSToken.LogicalNot:
						GenerateNode(gen,w.Operand);
						gen.Emit(OpCodes.Unbox_Any,typeof(bool));
						gen.Emit(OpCodes.Ldc_I4_0);
						gen.Emit(OpCodes.Ceq);
						gen.Emit(OpCodes.Box,typeof(bool));
						break;
					case JSToken.Minus:
						GenerateNode(gen,w.Operand);
						gen.Emit(OpCodes.Ldc_I4,-1);
						gen.Emit(OpCodes.Box,typeof(int));
						CallRuntimeMethod(gen,"Mul");
						break;
					default:
						throw new NotImplementedException();
				}
			}

			void GeneratePostOrPrefixOperator(ILGenerator gen,AST node)
			{
				PostOrPrefixOperatorWrapper w=new PostOrPrefixOperatorWrapper(node);
				LookupWrapper operand=new LookupWrapper(w.Operand);

				bool isPostfix=(w.OperatorTok==PostOrPrefixOperatorWrapper.PostOrPrefix.PostfixIncrement)||(w.OperatorTok==PostOrPrefixOperatorWrapper.PostOrPrefix.PostfixDecrement);
				bool isInc=(w.OperatorTok==PostOrPrefixOperatorWrapper.PostOrPrefix.PostfixIncrement)||(w.OperatorTok==PostOrPrefixOperatorWrapper.PostOrPrefix.PrefixIncrement);
				if ((!isPostfix)&&(!isInc)&&(w.OperatorTok!=PostOrPrefixOperatorWrapper.PostOrPrefix.PrefixDecrement))
					throw new NotImplementedException(); //nemelo by nastat

				if (_localsGeneration==LocalsGeneration.Local)
				{
					PreSetVar(gen,operand);
					GetVar(gen,operand);
					if (isPostfix)
						gen.Emit(OpCodes.Dup);
					gen.Emit(OpCodes.Ldc_I4_1);
					gen.Emit(OpCodes.Box,typeof(int));
					CallRuntimeMethod(gen,isInc?"Add":"Sub");
					if (!isPostfix)
						gen.Emit(OpCodes.Dup);
					SetVar(gen,operand);
				}
				else
				{
					LocalBuilder res=gen.DeclareLocal(_objectType);
					PreSetVar(gen,operand);
					GetVar(gen,operand);
					if (isPostfix)
					{
						gen.Emit(OpCodes.Dup);
						gen.Emit(OpCodes.Stloc,res);
					}
					gen.Emit(OpCodes.Ldc_I4_1);
					gen.Emit(OpCodes.Box,typeof(int));
					CallRuntimeMethod(gen,isInc?"Add":"Sub");
					if (!isPostfix)
					{
						gen.Emit(OpCodes.Dup);
						gen.Emit(OpCodes.Stloc,res);
					}
					SetVar(gen,operand);
					gen.Emit(OpCodes.Ldloc,res);
				}

				_functions.Peek().Pushes++;

				#region jednotlive casti rozepsane
				/*switch (w.OperatorTok)
				{
					case PostOrPrefixOperatorWrapper.PostOrPrefix.PostfixIncrement:
						GetVar(gen,operand);
						gen.Emit(OpCodes.Dup);
						_pushes[gen]++;
						CallRuntimeMethod(gen,"ConvertToNumber");
						gen.Emit(OpCodes.Ldc_R8,(double)1);
						gen.Emit(OpCodes.Add);
						gen.Emit(OpCodes.Box,typeof(double));
						SetVar(gen,operand);
						break;
					case PostOrPrefixOperatorWrapper.PostOrPrefix.PostfixDecrement:
						GetVar(gen,operand);
						CallRuntimeMethod(gen,"ConvertToNumber");
						gen.Emit(OpCodes.Ldc_R8,(double)1);
						gen.Emit(OpCodes.Sub);
						gen.Emit(OpCodes.Box,typeof(double));
						gen.Emit(OpCodes.Dup);
						_pushes[gen]++;
						SetVar(gen,operand);
						break;
					case PostOrPrefixOperatorWrapper.PostOrPrefix.PrefixIncrement:
						GetVar(gen,operand);
						CallRuntimeMethod(gen,"ConvertToNumber");
						gen.Emit(OpCodes.Ldc_R8,(double)1);
						gen.Emit(OpCodes.Add);
						gen.Emit(OpCodes.Box,typeof(double));
						gen.Emit(OpCodes.Dup);
						_pushes[gen]++;
						SetVar(gen,operand);
						break;
					case PostOrPrefixOperatorWrapper.PostOrPrefix.PrefixDecrement:
						GetVar(gen,operand);
						CallRuntimeMethod(gen,"ConvertToNumber");
						gen.Emit(OpCodes.Ldc_R8,(double)1);
						gen.Emit(OpCodes.Sub);
						gen.Emit(OpCodes.Box,typeof(double));
						gen.Emit(OpCodes.Dup);
						_pushes[gen]++;
						SetVar(gen,operand);
						break;
					default:
						throw new NotImplementedException(); //nemelo by nastat
				}*/
				#endregion jednotlive casti rozepsane
			}

			/*void GenerateTypeof(ILGenerator gen,AST node)
			{
				TypeofWrapper w=new TypeofWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateVoidOp(ILGenerator gen,AST node)
			{
				VoidOpWrapper w=new VoidOpWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateArrayLiteral(ILGenerator gen,AST node)
			{
				ASTListWrapper w=new ASTListWrapper(new ArrayLiteralWrapper(node).Elements);

				int initvaluescount=w.Count;
				AST[] initvalues=w.List;

				Type orgType=typeof(Jsil.Runtime.ArrayObject);
				gen.Emit(OpCodes.Newobj,GetRuntimeConstructor(orgType.GetConstructor(Type.EmptyTypes)));
				if (initvaluescount!=0)
				{
					MethodInfo mi=GetRuntimeMethod(orgType.GetMethod("push",BindingFlags.Public|BindingFlags.Instance));
					for (var a=0;a<initvaluescount;a++)
					{
						gen.Emit(OpCodes.Dup);
						GenerateNode(gen,initvalues[a]);
						gen.Emit(OpCodes.Call,mi);
						_functions.Peek().Pushes--;
						gen.Emit(OpCodes.Pop);
					}
				}
				//gen.Emit(OpCodes.Castclass,_objectType);
				_functions.Peek().Pushes++;
			}

			/*void GenerateAssemblyCustomAttributeList(ILGenerator gen,AST node)
			{
				AssemblyCustomAttributeListWrapper w=new AssemblyCustomAttributeListWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateASTList(ILGenerator gen,AST node)
			{
				ASTListWrapper w=new ASTListWrapper(node);

				int count=w.Count;
				AST[] list=w.List;
				for (var a=0;a<count;a++)
					GenerateNode(gen,list[a]);
			}

			/*void GenerateBinaryOp(ILGenerator gen,AST node)
			{
				BinaryOpWrapper w=new BinaryOpWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateBitwiseBinary(ILGenerator gen,AST node)
			{
				BitwiseBinaryWrapper w=new BitwiseBinaryWrapper(node);

				bool isOr=w.OperatorTok==JSToken.BitwiseOr;
				if (!(isOr||w.OperatorTok==JSToken.BitwiseAnd))
					throw new NotImplementedException();

				GenerateNode(gen,w.Operand1);
				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				GenerateNode(gen,w.Operand2);
				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				gen.Emit(isOr?OpCodes.Or:OpCodes.And);
				_functions.Peek().Pushes--;
			}

			/*void GenerateBitwiseBinaryAssign(ILGenerator gen,AST node)
			{
				BitwiseBinaryAssignWrapper w=new BitwiseBinaryAssignWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateEquality(ILGenerator gen,AST node)
			{
				EqualityWrapper w=new EqualityWrapper(node);

				GenerateNode(gen,w.Operand1);
				GenerateNode(gen,w.Operand2);
				CallRuntimeMethod(gen,"Equals");
				if (w.OperatorTok==JSToken.NotEqual)
				{
					gen.Emit(OpCodes.Ldc_I4_0);
					gen.Emit(OpCodes.Ceq);
				}
				gen.Emit(OpCodes.Box,typeof(bool));
				_functions.Peek().Pushes--;
			}

			/*void GenerateIn(ILGenerator gen,AST node)
			{
				InWrapper w=new InWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateInstanceof(ILGenerator gen,AST node)
			{
				InstanceofWrapper w=new InstanceofWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateLogical_and(ILGenerator gen,AST node)
			{
				GenerateLogicalInternal(gen,node,OpCodes.Brfalse,OpCodes.Ldc_I4_0);
			}

			void GenerateLogical_or(ILGenerator gen,AST node)
			{
				GenerateLogicalInternal(gen,node,OpCodes.Brtrue,OpCodes.Ldc_I4_1);
			}

			void GenerateLogicalInternal(ILGenerator gen,AST node,OpCode jumpInstruction,OpCode jumpValueInstruction)
			{
				BinaryOpWrapper w=new BinaryOpWrapper(node);

				Label lJump=gen.DefineLabel();
				Label lEnd=gen.DefineLabel();

				GenerateNode(gen,w.Operand1);
				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				gen.Emit(jumpInstruction,lJump);
				GenerateNode(gen,w.Operand2);
				gen.Emit(OpCodes.Br,lEnd);
				gen.MarkLabel(lJump);
				gen.Emit(jumpValueInstruction);
				gen.Emit(OpCodes.Box,typeof(bool));
				gen.MarkLabel(lEnd);
				_functions.Peek().Pushes--;
			}

			void GeneratePlus(ILGenerator gen,AST node)
			{
				GeneratePlusInternal(gen,new PlusWrapper(node));
			}

			void GeneratePlusAssign(ILGenerator gen,AST node)
			{
				PlusAssignWrapper w=new PlusAssignWrapper(node);
				LookupWrapper op=new LookupWrapper(w.Operand1);
				PreSetVar(gen,op);
				GeneratePlusInternal(gen,w);
				SetVar(gen,op);
			}

			void GeneratePlusInternal(ILGenerator gen,BinaryOpWrapper w)
			{
				GenerateNode(gen,w.Operand1);
				GenerateNode(gen,w.Operand2);
				CallRuntimeMethod(gen,"Add");
				_functions.Peek().Pushes--;
			}

			/*void GenerateComma(ILGenerator gen,AST node)
			{
				CommaWrapper w=new CommaWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateNumericBinary(ILGenerator gen,AST node)
			{
				NumericBinaryWrapper w=new NumericBinaryWrapper(node);

				GenerateNode(gen,w.Operand1);
				GenerateNode(gen,w.Operand2);

				switch (w.OperatorTok)
				{
					case JSToken.Minus:
						CallRuntimeMethod(gen,"Sub");
						break;
					case JSToken.Divide:
						CallRuntimeMethod(gen,"Div");
						break;
					case JSToken.Multiply:
						CallRuntimeMethod(gen,"Mul");
						break;
					case JSToken.Modulo:
						CallRuntimeMethod(gen,"Rem");
						break;
					default:
						throw new NotImplementedException(); //nemelo by nastat
				}

				//gen.Emit(OpCodes.Box,typeof(double));
				_functions.Peek().Pushes--;
			}

			/*void GenerateNumericBinaryAssign(ILGenerator gen,AST node)
			{
				NumericBinaryAssignWrapper w=new NumericBinaryAssignWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateRelational(ILGenerator gen,AST node)
			{
				RelationalWrapper w=new RelationalWrapper(node);

				GenerateNode(gen,w.Operand1);
				GenerateNode(gen,w.Operand2);

				bool compareToM1=(w.OperatorTok==JSToken.LessThan)||(w.OperatorTok==JSToken.GreaterThanEqual);
				bool negate=(w.OperatorTok==JSToken.LessThanEqual)||(w.OperatorTok==JSToken.GreaterThanEqual);
				if ((!compareToM1)&&(!negate)&&(w.OperatorTok!=JSToken.GreaterThan))
					throw new NotImplementedException(); //nemelo by nastat

				CallRuntimeMethod(gen,"Compare");
				gen.Emit(compareToM1?OpCodes.Ldc_I4_M1:OpCodes.Ldc_I4_1);
				gen.Emit(OpCodes.Ceq);
				if (negate)
				{
					gen.Emit(OpCodes.Ldc_I4_0);
					gen.Emit(OpCodes.Ceq);
				}
				gen.Emit(OpCodes.Box,typeof(bool));
				_functions.Peek().Pushes--;

				#region jednotlive casti rozepsane
				/*switch (w.OperatorTok)
					{
						case JSToken.LessThan:
							CallRuntimeMethod(gen,"Compare");
							gen.Emit(OpCodes.Ldc_I4_M1);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Box,typeof(bool));
							_pushes[gen]--;
							break;
						case JSToken.GreaterThan:
							CallRuntimeMethod(gen,"Compare");
							gen.Emit(OpCodes.Ldc_I4_1);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Box,typeof(bool));
							_pushes[gen]--;
							break;
						case JSToken.LessThanEqual:
							CallRuntimeMethod(gen,"Compare");
							gen.Emit(OpCodes.Ldc_I4_1);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Ldc_I4_0);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Box,typeof(bool));
							_pushes[gen]--;
							break;
						case JSToken.GreaterThanEqual:
							CallRuntimeMethod(gen,"Compare");
							gen.Emit(OpCodes.Ldc_I4_M1);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Ldc_I4_0);
							gen.Emit(OpCodes.Ceq);
							gen.Emit(OpCodes.Box,typeof(bool));
							_pushes[gen]--;
							break;
						default:
							throw new NotImplementedException(); //nemelo by nastat
					}*/
				#endregion jednotlive casti rozepsane
			}

			/*void GenerateStrictEquality(ILGenerator gen,AST node)
			{
				StrictEqualityWrapper w=new StrictEqualityWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateBinding(ILGenerator gen,AST node)
			{
				BindingWrapper w=new BindingWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateCallableExpression(ILGenerator gen,AST node)
			{
				CallableExpressionWrapper w=new CallableExpressionWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateLookup(ILGenerator gen,AST node)
			{
				LookupWrapper w=new LookupWrapper(node);
				if (_externalLibs.Contains(w.Name))
				{
					gen.Emit(OpCodes.Ldarg_0);
					gen.Emit(OpCodes.Ldstr,w.Name);
					CallRuntimeMethod(gen,"GetExternalLibrary");
				}
				else
					GetVar(gen,w);
			}

			void GenerateMember(ILGenerator gen,AST node)
			{
				MemberWrapper w=new MemberWrapper(node);
				if (ThisLiteralWrapper.CheckType(w.RootObject))
					GetVar(gen,w.Name,w.Context,true);
				else
				{
					gen.Emit(OpCodes.Ldarg_0);
					GenerateNode(gen,w.RootObject);
					gen.Emit(OpCodes.Ldstr,w.Name);

					AST parentNode=_nodeStack[_nodeStackLevel-1];
					if (CallWrapper.CheckType(parentNode))
					{
						CallWrapper cw=new CallWrapper(parentNode);
						ASTListWrapper argsW=new ASTListWrapper(cw.Args);
					}

					CallRuntimeMethod(gen,"GetMember");
				}
			}

			void GenerateBlock(ILGenerator gen,AST node)
			{
				BlockWrapper w=new BlockWrapper(node);

				int p=_functions.Peek().Pushes;
				foreach (AST item in w.List)
					GenerateNode(gen,item);
				FinalizeFunctionPushes(gen,_functions.Peek().Pushes-p);
			}

			void GenerateConstantWrapper(ILGenerator gen,AST node)
			{
				ConstantWrapperWrapper w=new ConstantWrapperWrapper(node);
				if (w.IsNumericLiteral)
				{
					Type type=w.Value.GetType();
					if (type==typeof(int))
						gen.Emit(OpCodes.Ldc_I4,(int)w.Value);
					else if (type==typeof(double))
						gen.Emit(OpCodes.Ldc_R8,(double)w.Value);
					else
						throw new NotImplementedException();
					gen.Emit(OpCodes.Box,type);
				}
				else
				{
					if (w.Value is bool)
					{
						gen.Emit((bool)w.Value?OpCodes.Ldc_I4_1:OpCodes.Ldc_I4_0);
						gen.Emit(OpCodes.Box,typeof(bool));
					}
					else
					{
						gen.Emit(OpCodes.Ldstr,(string)w.Value);
						gen.Emit(OpCodes.Box,typeof(string));
					}
				}
				_functions.Peek().Pushes++;
			}

			/*void GenerateEmptyLiteral(ILGenerator gen,AST node)
			{
				EmptyLiteralWrapper w=new EmptyLiteralWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateNullLiteral(ILGenerator gen,AST node)
			{
				//NullLiteralWrapper w=new NullLiteralWrapper(node);
				gen.Emit(OpCodes.Ldnull);
				_functions.Peek().Pushes++;
			}

			/*void GenerateConstructorCall(ILGenerator gen,AST node)
			{
				ConstructorCallWrapper w=new ConstructorCallWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateCustomAttributeList(ILGenerator gen,AST node)
			{
				CustomAttributeListWrapper w=new CustomAttributeListWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateDebugBreak(ILGenerator gen,AST node)
			{
				//DebugBreakWrapper w=new DebugBreakWrapper(node);

				if (_debug)
				{
					CallRuntimeMethod(gen,"Debug");
					gen.Emit(OpCodes.Pop);
				}
			}

			/*void GenerateEval(ILGenerator gen,AST node)
			{
				EvalWrapper w=new EvalWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateForIn(ILGenerator gen,AST node)
			{
				ForInWrapper w=new ForInWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateFunctionDeclaration(ILGenerator gen,AST node)
			{
				FunctionDeclarationWrapper w=new FunctionDeclarationWrapper(node);
				FunctionObjectWrapper w2=new FunctionObjectWrapper(w.Func);
				GenerateFunctionObject(gen,w.Name,w2,w.Context);
			}

			void GenerateFunctionObject(ILGenerator gen,string functionName,FunctionObjectWrapper w2,Context context)
			{
				/*if (_localsGeneration==LocalsGeneration.Local)
				{
					_functionsLevel++;

					FunctionInfo functionInfo=new FunctionInfo() { FunObj=w2 };
					if (_functions.Count<=_functionsLevel)
						_functions.Insert(_functionsLevel,functionInfo);
					else
						_functions[_functionsLevel]=functionInfo;
					if (_methods.Count<=_functionsLevel)
						_methods.Insert(_functionsLevel,new Dictionary<string,FieldBuilder>());
					else
						_methods[_functionsLevel]=new Dictionary<string,FieldBuilder>();

					ParameterDeclarationWrapper[] parameterDeclarations=w2.ParameterDeclarations;
					int count=parameterDeclarations.Length;
					Type[] parameterTypes=new Type[count];
					for (int a=0;a<count;a++)
						parameterTypes[a]=_objectType;
					MethodBuilder m=_typBldr.DefineMethod("fun "+functionName,MethodAttributes.HideBySig|MethodAttributes.Private,_objectType,parameterTypes);
					for (int a=0;a<count;a++)
						m.DefineParameter(a+1,ParameterAttributes.None,parameterDeclarations[a].Name);

					FieldBuilder fb=_typBldr.DefineField(functionName,_objectType,FieldAttributes.Public);
					_methods[_functionsLevel].Add(functionName,fb);

					PreSetVar(gen,functionName,context);
					gen.Emit(OpCodes.Ldarg_0);
					gen.Emit(OpCodes.Ldftn,m);
					gen.Emit(OpCodes.Newobj,GetRuntimeConstructor(RuntimeMethods.GetFuncType(count).GetConstructors()[0]));
					_pushes[gen]++;
					SetVar(gen,functionName,context);

					_varInfo.Add(new Dictionary<string,object>());

					gen=m.GetILGenerator();
					_pushes.Add(gen,0);
					_loopLabels.Add(gen,new Stack<LoopLabels>());

					functionInfo.EndLabel=gen.DefineLabel();
					functionInfo.ResultValue=gen.DeclareLocal(_objectType);

					gen.Emit(OpCodes.Ldnull);
					gen.Emit(OpCodes.Stloc,functionInfo.ResultValue);
					GenerateNode(gen,w2.Body);
					gen.MarkLabel(functionInfo.EndLabel);
					gen.Emit(OpCodes.Ldloc,functionInfo.ResultValue);
					gen.Emit(OpCodes.Ret);

					_varInfo.RemoveAt(_varInfo.Count-1);
					_functionsLevel--;
				}
				else
				{*/
					FieldBuilder fb=_typBldr.DefineField(functionName,_objectType,FieldAttributes.Public);
					_functions.Peek().Variables.Add(functionName,fb);

					Type fobType=GetRuntimeType(typeof(Jsil.Runtime.FunctionObjectBase));
					TypeBuilder newTb=_modBldr.DefineType(functionName+"~fun",TypeAttributes.BeforeFieldInit|TypeAttributes.Sealed,fobType);
					ConstructorBuilder cb=newTb.DefineConstructor(MethodAttributes.Assembly,CallingConventions.Standard,new Type[] { GetRuntimeType(typeof(Jsil.Runtime.GlobalObject)) });
					TypeBuilder oldTb=_typBldr;
					_typBldr=newTb;

					ParameterDeclarationWrapper[] parameterDeclarations=w2.ParameterDeclarations;
					int count=parameterDeclarations.Length;
					Type[] parameterTypes=new Type[count];
					for (int a=0;a<count;a++)
						parameterTypes[a]=_objectType;
					MethodBuilder m=_typBldr.DefineMethod("fun "+functionName,MethodAttributes.HideBySig|MethodAttributes.Assembly,_objectType,parameterTypes);
					for (int a=0;a<count;a++)
						m.DefineParameter(a+1,ParameterAttributes.None,parameterDeclarations[a].Name);

					ILGenerator newGen=m.GetILGenerator();
					Label endLabel=newGen.DefineLabel();
					LocalBuilder resultValue=newGen.DeclareLocal(_objectType);

					_functions.Push(new FunctionInfo() { FunObj=w2,EndLabel=endLabel,ResultValue=resultValue });

					MarkSequencePoint(newGen,w2.Body);
					newGen.Emit(OpCodes.Ldnull);
					newGen.Emit(OpCodes.Stloc,resultValue);
					GenerateNode(newGen,w2.Body);
					newGen.MarkLabel(endLabel);
					newGen.Emit(OpCodes.Ldloc,resultValue);
					newGen.Emit(OpCodes.Ret);

					FunctionInfo fi=_functions.Pop();

					_createdFunctions.Add(_typBldr);
					_typBldr=oldTb;

					////////////////////////////////
					newGen=cb.GetILGenerator();
					newGen.Emit(OpCodes.Ldarg_0); //base(arg1)
					newGen.Emit(OpCodes.Ldarg_1);
					newGen.Emit(OpCodes.Call,GetRuntimeConstructor(fobType.GetConstructors()[0]));
					DefineVariables(cb,fi);
					newGen.Emit(OpCodes.Ret);

					////////////////////////////////
					PreSetVar(gen,functionName,context);
					gen.Emit(OpCodes.Ldarg_0); //arg pro .ctor
					gen.Emit(OpCodes.Newobj,cb);
					gen.Emit(OpCodes.Ldftn,m);
					gen.Emit(OpCodes.Newobj,GetRuntimeConstructor(RuntimeMethods.GetFuncType(count).GetConstructors()[0]));
					_functions.Peek().Pushes++;
					SetVar(gen,functionName,context);
				//}
			}

			void GenerateFunctionObject2(ILGenerator gen,string functionName,FunctionObjectWrapper w2,Context context)
			{
				/*FieldBuilder fb=_typBldr.DefineField(functionName,_objectType,FieldAttributes.Public);
				_functions.Peek().Variables.Add(functionName,fb);*/

				Type fobType=GetRuntimeType(typeof(Jsil.Runtime.FunctionObjectBase));
				TypeBuilder newTb=_modBldr.DefineType(functionName+"~obj",TypeAttributes.BeforeFieldInit|TypeAttributes.Sealed,fobType);
				ConstructorBuilder cb=newTb.DefineConstructor(MethodAttributes.Assembly,CallingConventions.Standard,new Type[] { GetRuntimeType(typeof(Jsil.Runtime.GlobalObject)) });
				TypeBuilder oldTb=_typBldr;
				_typBldr=newTb;

				ParameterDeclarationWrapper[] parameterDeclarations=w2.ParameterDeclarations;
				int count=parameterDeclarations.Length;
				Type[] parameterTypes=new Type[count];
				for (int a=0;a<count;a++)
					parameterTypes[a]=_objectType;
				MethodBuilder m=_typBldr.DefineMethod("fun "+functionName,MethodAttributes.HideBySig|MethodAttributes.Assembly,_objectType,parameterTypes);
				for (int a=0;a<count;a++)
					m.DefineParameter(a+1,ParameterAttributes.None,parameterDeclarations[a].Name);

				ILGenerator newGen=m.GetILGenerator();
				Label endLabel=newGen.DefineLabel();
				LocalBuilder resultValue=newGen.DeclareLocal(_objectType);

				_functions.Push(new FunctionInfo() { FunObj=w2,EndLabel=endLabel,ResultValue=resultValue });

				MarkSequencePoint(newGen,w2.Body);
				newGen.Emit(OpCodes.Ldnull);
				newGen.Emit(OpCodes.Stloc,resultValue);
				GenerateNode(newGen,w2.Body);
				newGen.MarkLabel(endLabel);
				newGen.Emit(OpCodes.Ldloc,resultValue);
				newGen.Emit(OpCodes.Ret);

				FunctionInfo fi=_functions.Pop();

				_createdFunctions.Add(_typBldr);
				_typBldr=oldTb;

				////////////////////////////////
				newGen=cb.GetILGenerator();
				newGen.Emit(OpCodes.Ldarg_0); //base(arg1)
				newGen.Emit(OpCodes.Ldarg_1);
				newGen.Emit(OpCodes.Call,GetRuntimeConstructor(fobType.GetConstructors()[0]));

				newGen.Emit(OpCodes.Ldarg_0);
				newGen.Emit(OpCodes.Call,m);
				DefineVariables(cb,fi);
				newGen.Emit(OpCodes.Ret);

				////////////////////////////////
				//PreSetVar(gen,functionName,context);
				gen.Emit(OpCodes.Ldarg_0); //arg pro .ctor
				gen.Emit(OpCodes.Newobj,cb);
				//gen.Emit(OpCodes.Ldftn,m);
				//gen.Emit(OpCodes.Newobj,GetRuntimeConstructor(RuntimeMethods.GetFuncType(count).GetConstructors()[0]));
				_functions.Peek().Pushes++;
				//SetVar(gen,functionName,context);
			}

			void GenerateFunctionExpression(ILGenerator gen,AST node)
			{
				FunctionExpressionWrapper w=new FunctionExpressionWrapper(node);
				FunctionObjectWrapper w2=new FunctionObjectWrapper(w.Func);

				GenerateFunctionObject(gen,w.Name,w2,w.Context);
				GetVar(gen,w.Name,w.Context);
			}

			void GenerateImport(ILGenerator gen,AST node)
			{
				_externalLibs.Add(ImportWrapper.GetName(node));
			}

			/*void GeneratePackage(ILGenerator gen,AST node)
			{
				PackageWrapper w=new PackageWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateScriptBlock(ILGenerator gen,AST node)
			{
				ScriptBlockWrapper w=new ScriptBlockWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateThrow(ILGenerator gen,AST node)
			{
				ThrowWrapper w=new ThrowWrapper(node);

				GenerateNode(gen,w.Operand);
				gen.Emit(OpCodes.Throw);
				_functions.Peek().Pushes--;
			}

			void GenerateTry(ILGenerator gen,AST node)
			{
				TryWrapper w=new TryWrapper(node);

				string exceptionVarName=w.ExceptionVariableName;

				gen.BeginExceptionBlock();
				GenerateNode(gen,w.Body);
				gen.BeginCatchBlock(typeof(Exception));

				SortedDictionary<string,object> variables=_functions.Peek().Variables;

				if (!variables.ContainsKey(exceptionVarName))
					if (_localsGeneration==LocalsGeneration.Field)
						variables.Add(exceptionVarName,_typBldr.DefineField(exceptionVarName,_objectType,FieldAttributes.Public));
					else
					{
						LocalBuilder var=gen.DeclareLocal(_objectType);
						if (_debug)
						{
							Context c=w.Context;
							var.SetLocalSymInfo(exceptionVarName,c.StartPosition,c.EndPosition);
						}
						variables.Add(exceptionVarName,var);
					}

				if (_localsGeneration==LocalsGeneration.Field)
				{
					LocalBuilder var=gen.DeclareLocal(_objectType);
					gen.Emit(OpCodes.Stloc,var);
					PreSetVar(gen,exceptionVarName,w.Context);
					gen.Emit(OpCodes.Ldloc,var);
					CallRuntimeMethod(gen,"MakeJsError");
					SetVar(gen,exceptionVarName,w.Context);
				}
				else
					SetVar(gen,exceptionVarName,w.Context);

				GenerateNode(gen,w.Handler);
				gen.EndExceptionBlock();
			}

			/*void GenerateTypeExpression(ILGenerator gen,AST node)
			{
				TypeExpressionWrapper w=new TypeExpressionWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateWith(ILGenerator gen,AST node)
			{
				WithWrapper w=new WithWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateAssign(ILGenerator gen,AST node)
			{
				AssignWrapper w=new AssignWrapper(node);
				if (CallWrapper.CheckType(w.Lhside))
				{
					//prirazeni do pole
					CallWrapper w2=new CallWrapper(w.Lhside);
					GenerateNode(gen,w2.Func); //pushne pole
					GenerateNode(gen,new ASTListWrapper(w2.Args).List[0]);
					GenerateNode(gen,w.Rhside);
					CallRuntimeMethod(gen,"SetArrayItem");
					_functions.Peek().Pushes-=3;
				}
				else
				{
					if (LookupWrapper.CheckType(w.Lhside))
					{
						LookupWrapper lw=new LookupWrapper(w.Lhside);
						PreSetVar(gen,lw);
						GenerateNode(gen,w.Rhside);
						SetVar(gen,lw);
					}
					else
					{
						MemberWrapper mw=new MemberWrapper(w.Lhside);
						if (ThisLiteralWrapper.CheckType(mw.RootObject))
						{
							PreSetVar(gen,mw,true);
							GenerateNode(gen,w.Rhside);
							SetVar(gen,mw,true);
						}
						else
						{
							gen.Emit(OpCodes.Ldarg_0);
							GenerateNode(gen,mw.RootObject);
							gen.Emit(OpCodes.Ldstr,mw.Name);
							GenerateNode(gen,w.Rhside);
							CallRuntimeMethod(gen,"SetMember");
							_functions.Peek().Pushes-=2;
						}
					}
				}
			}

			void GenerateBreak(ILGenerator gen,AST node)
			{
				//BreakWrapper w=new BreakWrapper(node);
				gen.Emit(OpCodes.Br,_functions.Peek().LoopLabels.Peek().Finish);
			}

			void GenerateCall(ILGenerator gen,AST node)
			{
				CallWrapper w=new CallWrapper(node);
				ASTListWrapper argsW=new ASTListWrapper(w.Args);

				if (w.IsArray)
				{
					GenerateNode(gen,w.Func);
					GenerateNode(gen,argsW.List[0]);
					CallRuntimeMethod(gen,"GetArrayItem");
					_functions.Peek().Pushes--;
				}
				else if (w.IsConstructor)
				{
					if (LookupWrapper.CheckType(w.Func))
					{
						string objName=new LookupWrapper(w.Func).Name;
						int argsCount=argsW.Count;
						Type[] types=new Type[argsCount];
						for (int a=0;a<argsCount;a++)
							types[a]=_objectType;
						switch (objName)
						{
							case "Date":
								GenerateNode(gen,w.Args);
								_functions.Peek().Pushes-=argsCount;
								gen.Emit(OpCodes.Newobj,GetRuntimeType(typeof(Jsil.Runtime.DateObject)).GetConstructor(types));
								_functions.Peek().Pushes++;
								break;
							case "Error":
								if (argsCount!=2)
									throw new RuntimeException(RuntimeExceptionReason.NoCompatibleMethod,objName,".ctor",argsCount);
								GenerateNode(gen,w.Args);
								_functions.Peek().Pushes-=argsCount;
								gen.Emit(OpCodes.Newobj,GetRuntimeType(typeof(Jsil.Runtime.JsError)).GetConstructor(types));
								_functions.Peek().Pushes++;
								break;
							default:
								throw new CompilerException(CompilerExceptionReason.UnknownObjectType,new object[] { objName });
						}
					}
					else if (FunctionExpressionWrapper.CheckType(w.Func))
					{
						FunctionExpressionWrapper w1=new FunctionExpressionWrapper(w.Func);
						FunctionObjectWrapper w2=new FunctionObjectWrapper(w1.Func);

						GenerateFunctionObject2(gen,w1.Name,w2,w.Context);
					}
					else if (MemberWrapper.CheckType(w.Func))
					{
						int argsCount=argsW.Count;
						GenerateNode(gen,w.Func);
						Type type=typeof(StaticObject);
						gen.Emit(OpCodes.Castclass,type);
						gen.Emit(OpCodes.Ldfld,type.GetField("Type"));
						GenerateNode(gen,w.Args);
						_functions.Peek().Pushes-=argsCount;
						CallRuntimeMethod(gen,RuntimeMethods.GetDelegateConstuctor(argsCount));
						_functions.Peek().Pushes++;
					}
					else
						throw new NotImplementedException();
				}
				else
				{
					int argsCount=argsW.Count;

					GenerateNode(gen,w.Func);
					for (int a=0;a<argsCount;a++)
						GenerateNode(gen,argsW.List[a]);
					_functions.Peek().Pushes-=argsCount;
					CallRuntimeMethod(gen,Array.Find(typeof(DynamDelCalls).GetMethods(),x => (x.Name=="Call")&&(x.GetParameters().Length==argsCount+1)));

					if (ExpressionWrapper.CheckType(_nodeStack[_nodeStackLevel-1]))
					{
						gen.Emit(OpCodes.Pop);
						_functions.Peek().Pushes--;
					}
				}
			}

			/*void GenerateClass(ILGenerator gen,AST node)
			{
				ClassWrapper w=new ClassWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateEnumDeclaration(ILGenerator gen,AST node)
			{
				EnumDeclarationWrapper w=new EnumDeclarationWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateConditional(ILGenerator gen,AST node)
			{
				ConditionalWrapper w=new ConditionalWrapper(node);
				GenerateIf(gen,w.Condition,w.Operand1,w.Operand2,false);
			}

			void GenerateIf(ILGenerator gen,AST condition,AST operand1,AST operand2,bool realIf)
			{
				if (operand2==null)
				{
					Label labelFinish=gen.DefineLabel();

					GenerateNode(gen,condition);
					gen.Emit(OpCodes.Unbox_Any,typeof(bool));
					gen.Emit(OpCodes.Brfalse,labelFinish);
					_functions.Peek().Pushes--;

					int s=_functions.Peek().Pushes;
					GenerateNode(gen,operand1);
					if (_functions.Peek().Pushes-s!=(realIf?0:1))
						throw new CompilerException(CompilerExceptionReason.InvalidConditionalOperand,operand1);

					gen.MarkLabel(labelFinish);
				}
				else
				{
					Label labelFinish=gen.DefineLabel();
					Label labelElse=gen.DefineLabel();

					GenerateNode(gen,condition);
					gen.Emit(OpCodes.Unbox_Any,typeof(bool));
					gen.Emit(OpCodes.Brtrue,labelElse);
					_functions.Peek().Pushes--;

					int s=_functions.Peek().Pushes;
					GenerateNode(gen,operand2);
					if (_functions.Peek().Pushes-s!=(realIf?0:1))
						throw new CompilerException(CompilerExceptionReason.InvalidConditionalOperand,operand2);

					gen.Emit(OpCodes.Br,labelFinish);
					gen.MarkLabel(labelElse);
					s=_functions.Peek().Pushes;
					GenerateNode(gen,operand1);
					if (_functions.Peek().Pushes-s!=(realIf?0:1))
						throw new CompilerException(CompilerExceptionReason.InvalidConditionalOperand,operand1);

					gen.MarkLabel(labelFinish);
				}
				if (!realIf)
					_functions.Peek().Pushes--;
			}

			/*void GenerateConstant(ILGenerator gen,AST node)
			{
				ConstantWrapper w=new ConstantWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateContinue(ILGenerator gen,AST node)
			{
				//ContinueWrapper w=new ContinueWrapper(node);
				gen.Emit(OpCodes.Br,_functions.Peek().LoopLabels.Peek().Next);
			}

			/*void GenerateCustomAttribute(ILGenerator gen,AST node)
			{
				CustomAttributeWrapper w=new CustomAttributeWrapper(node);

				throw new NotImplementedException();
			}*/

			/*void GenerateDoWhile(ILGenerator gen,AST node)
			{
				DoWhileWrapper w=new DoWhileWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateExpression(ILGenerator gen,AST node)
			{
				GenerateNode(gen,new ExpressionWrapper(node).Operand);
			}

			void GenerateFor(ILGenerator gen,AST node)
			{
				ForWrapper w=new ForWrapper(node);
				//moje verze smycky
				Label forBegin=gen.DefineLabel();
				Label forEnd=gen.DefineLabel();
				Label forNext=gen.DefineLabel();
				_functions.Peek().LoopLabels.Push(new LoopLabels() { Next=forNext,Finish=forEnd });

				GenerateNode(gen,w.Initializer);
				gen.MarkLabel(forBegin);
				GenerateNode(gen,w.Condition);
				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				gen.Emit(OpCodes.Brfalse,forEnd);
				_functions.Peek().Pushes--;

				int p=_functions.Peek().Pushes;
				GenerateNode(gen,w.Body);
				FinalizeFunctionPushes(gen,_functions.Peek().Pushes-p);
				gen.MarkLabel(forNext);
				p=_functions.Peek().Pushes;
				GenerateNode(gen,w.Incrementer);
				FinalizeFunctionPushes(gen,_functions.Peek().Pushes-p);
				gen.Emit(OpCodes.Br,forBegin);
				gen.MarkLabel(forEnd);
				_functions.Peek().LoopLabels.Pop();

				#region ms version
				/*jina verze: zaklad je dle MS compileru
				/Label labelFor=gen.DefineLabel();
				Label labelForLoop=gen.DefineLabel();

				GenerateNode(gen,w.Initializer);

				gen.Emit(OpCodes.Br,labelFor);
				gen.MarkLabel(labelForLoop);

				GenerateNode(gen,w.Body);
				GenerateNode(gen,w.Incrementer);

				gen.MarkLabel(labelFor);

				GenerateNode(gen,w.Condition);

				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				gen.Emit(OpCodes.Brtrue,labelForLoop);
				_pushes[gen]--;
				*/
				#endregion ms version
			}

			/*void GenerateIdentifierLiteral(ILGenerator gen,AST node)
			{
				IdentifierLiteralWrapper w=new IdentifierLiteralWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateIf(ILGenerator gen,AST node)
			{
				IfWrapper w=new IfWrapper(node);
				GenerateIf(gen,w.Condition,w.Operand1,w.Operand2,true);
			}

			void GenerateObjectLiteral(ILGenerator gen,AST node)
			{
				ObjectLiteralWrapper w=new ObjectLiteralWrapper(node);

				TypeBuilder newTb=_modBldr.DefineType("~object~"+node.GetHashCode(),TypeAttributes.BeforeFieldInit|TypeAttributes.Sealed|TypeAttributes.Public,_objectType);
				_createdFunctions.Add(newTb);

				ConstructorBuilder cb=newTb.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,Type.EmptyTypes);
				ILGenerator newGen=cb.GetILGenerator();
				newGen.Emit(OpCodes.Ldarg_0);
				newGen.Emit(OpCodes.Call,_objectType.GetConstructor(Type.EmptyTypes));
				newGen.Emit(OpCodes.Ret);

				//gen.Emit(OpCodes.Ldarg_0); //arg pro .ctor
				gen.Emit(OpCodes.Newobj,cb);
				_functions.Peek().Pushes++;

				int a=0;
				foreach (AST item in w.Keys)
				{
					if (!ConstantWrapperWrapper.CheckType(item))
						throw new CompilerException(CompilerExceptionReason.UnknownObjectType);

					string fName=new ConstantWrapperWrapper(item).Value as string;
					if (fName==null)
						throw new CompilerException(CompilerExceptionReason.UnknownObjectType);
					FieldBuilder fb=newTb.DefineField(fName,_objectType,FieldAttributes.Public);

					gen.Emit(OpCodes.Dup);
					GenerateNode(gen,w.Values[a++]);
					gen.Emit(OpCodes.Stfld,fb);
					_functions.Peek().Pushes--;
				}
			}

			/*void GeneratePrint(ILGenerator gen,AST node)
			{
				PrintWrapper w=new PrintWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateRegExpLiteral(ILGenerator gen,AST node)
			{
				RegExpLiteralWrapper w=new RegExpLiteralWrapper(node);
				gen.Emit(OpCodes.Ldstr,w.Source);
				gen.Emit(w.IgnoreCase?OpCodes.Ldc_I4_1:OpCodes.Ldc_I4_0);
				gen.Emit(w.Multiline?OpCodes.Ldc_I4_1:OpCodes.Ldc_I4_0);
				gen.Emit(w.Global?OpCodes.Ldc_I4_1:OpCodes.Ldc_I4_0);
				gen.Emit(OpCodes.Newobj,GetRuntimeType(typeof(Jsil.Runtime.RegExpObject)).GetConstructor(new Type[] { typeof(string),typeof(bool),typeof(bool),typeof(bool) }));
				_functions.Peek().Pushes++;
			}

			void GenerateReturn(ILGenerator gen,AST node)
			{
				ReturnWrapper w=new ReturnWrapper(node);

				AST operand=w.Operand;
				if (operand!=null)
				{
					GenerateNode(gen,operand);
					gen.Emit(OpCodes.Stloc,_functions.Peek().ResultValue);
					_functions.Peek().Pushes--;
				}
				gen.Emit(OpCodes.Br,_functions.Peek().EndLabel);
			}

			/*void GenerateStaticInitializer(ILGenerator gen,AST node)
			{
				StaticInitializerWrapper w=new StaticInitializerWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateSwitch(ILGenerator gen,AST node)
			{
				SwitchWrapper w=new SwitchWrapper(node);
				bool haveDefaultCase=w.DefaultCaseIndex!=-1;

				ASTListWrapper cases=new ASTListWrapper(w.Cases);
				int c=cases.Count;

				List<GenerateSwitchItem> preparedCases=new List<GenerateSwitchItem>(c);
				for (int a=c-(haveDefaultCase?2:1);a>=0;a--)
				{
					SwitchCaseWrapper sw=new SwitchCaseWrapper(cases.List[a]);

					GenerateSwitchItem item;
					if ((BlockWrapper.CheckType(sw.Statements))&&(new BlockWrapper(sw.Statements).List.Count==0))
						item=preparedCases[preparedCases.Count-1];
					else
					{
						item=new GenerateSwitchItem() { Statements=sw.Statements };
						preparedCases.Add(item);
					}
					item.CaseValues.Add(sw.CaseValue);
				}
				//////////////////////////////////

				LocalBuilder valueToCompare=gen.DeclareLocal(_objectType);
				GenerateNode(gen,w.Expression);
				gen.Emit(OpCodes.Stloc,valueToCompare);
				_functions.Peek().Pushes--;

				Label labelOverSwitch=gen.DefineLabel();
				_functions.Peek().LoopLabels.Push(new LoopLabels() { Finish=labelOverSwitch });

				preparedCases.Reverse();
				foreach (GenerateSwitchItem item in preparedCases)
				{
					item.CaseValues.Reverse();
					Label labelNextCase=gen.DefineLabel();

					c=item.CaseValues.Count;
					Label labelStatements=gen.DefineLabel();
					for (int a=0;a<c;a++)
					{
						GenerateNode(gen,item.CaseValues[a]);
						gen.Emit(OpCodes.Ldloc,valueToCompare);
						CallRuntimeMethod(gen,"Equals");
						gen.Emit(OpCodes.Ldc_I4_1);
						gen.Emit(OpCodes.Beq,labelStatements);
						_functions.Peek().Pushes--;
					}
					gen.Emit(OpCodes.Br,labelNextCase);
					gen.MarkLabel(labelStatements);
					GenerateNode(gen,item.Statements);
					gen.Emit(OpCodes.Br,labelOverSwitch);
					gen.MarkLabel(labelNextCase);
				}

				if (haveDefaultCase)
					GenerateNode(gen,new SwitchCaseWrapper(cases.List[w.DefaultCaseIndex]).Statements);

				_functions.Peek().LoopLabels.Pop();
				gen.MarkLabel(labelOverSwitch);
			}

			class GenerateSwitchItem
			{
				internal List<AST> CaseValues=new List<AST>();
				internal AST Statements;
			}

			/*void GenerateSwitchCase(ILGenerator gen,AST node)
			{
				SwitchCaseWrapper w=new SwitchCaseWrapper(node);

				throw new NotImplementedException();
			}*/

			void GenerateThisLiteral(ILGenerator gen,AST node)
			{
				//ThisLiteralWrapper w=new ThisLiteralWrapper(node);
				gen.Emit(OpCodes.Ldarg_0);
			}

			void GenerateVariableDeclaration(ILGenerator gen,AST node)
			{
				VariableDeclarationWrapper w=new VariableDeclarationWrapper(node);
				LookupWrapper id=new LookupWrapper(w.Identifier);

				SortedDictionary<string,object> variables=_functions.Peek().Variables;
				if (!variables.ContainsKey(id.Name))
					if (_localsGeneration==LocalsGeneration.Field)
						variables.Add(id.Name,_typBldr.DefineField(id.Name,_objectType,FieldAttributes.Public));
					else
					{
						LocalBuilder var=gen.DeclareLocal(_objectType);
						if (_debug)
						{
							Context c=id.Context;
							var.SetLocalSymInfo(id.Name,c.StartPosition,c.EndPosition);
						}
						variables.Add(id.Name,var);
					}

				AST init=w.Initializer;
				if (init!=null)
				{
					PreSetVar(gen,id);
					GenerateNode(gen,init);
					SetVar(gen,id);
				}
			}

			void GenerateWhile(ILGenerator gen,AST node)
			{
				WhileWrapper w=new WhileWrapper(node);

				//int p=_pushes[gen];

				Label forBegin=gen.DefineLabel();
				Label forEnd=gen.DefineLabel();
				Label forNext=gen.DefineLabel();
				_functions.Peek().LoopLabels.Push(new LoopLabels() { Next=forNext,Finish=forEnd });

				gen.MarkLabel(forBegin);
				GenerateNode(gen,w.Condition);
				gen.Emit(OpCodes.Unbox_Any,typeof(bool));
				gen.Emit(OpCodes.Brfalse,forEnd);
				_functions.Peek().Pushes--;

				int p=_functions.Peek().Pushes;
				GenerateNode(gen,w.Body);
				FinalizeFunctionPushes(gen,_functions.Peek().Pushes-p);
				gen.MarkLabel(forNext);
				gen.Emit(OpCodes.Br,forBegin);
				gen.MarkLabel(forEnd);
				_functions.Peek().LoopLabels.Pop();

				//FinalizeFunctionPushes(gen,_pushes[gen]-p);
			}
			#endregion generate methods

			#region RuntimeMethod
			void CallRuntimeMethod(ILGenerator gen,string methodName)
			{
				CallRuntimeMethod(gen,GetRuntimeMethod(methodName));
			}

			void CallRuntimeMethod(ILGenerator gen,MethodInfo rawRuntimeMethod)
			{
				gen.Emit(OpCodes.Call,GetRuntimeMethod(rawRuntimeMethod));
			}

			ConstructorInfo GetRuntimeConstructor(ConstructorInfo ci)
			{
				return _runtimeMethodsUsage==RuntimeMethodsUsage.Call?ci:_typeCopier.GetConstructorCopy(ci);
			}

			MethodInfo GetRuntimeMethod(MethodInfo mi)
			{
				return _runtimeMethodsUsage==RuntimeMethodsUsage.Call?mi:_typeCopier.GetMethodCopy(mi);
			}

			Type GetRuntimeType(Type type)
			{
				return _runtimeMethodsUsage==RuntimeMethodsUsage.Call?type:_typeCopier.GetTypeCopy(type);
			}

			FieldInfo GetRuntimeField(FieldInfo fi)
			{
				return _runtimeMethodsUsage==RuntimeMethodsUsage.Call?fi:_typeCopier.GetFieldCopy(fi);
			}

			MethodInfo GetRuntimeMethod(string methodName)
			{
				return typeof(Jsil.Runtime.RuntimeMethods).GetMethod(methodName,BindingFlags.Public|BindingFlags.Static);
			}
			#endregion RuntimeMethod

			#region get/set vars
			int GetVarType(string name,Context context,bool isThis,out object info)
			{
				foreach (FunctionInfo item in _functions)
				{
					if (item.FunObj!=null)
					{
						int index=Array.FindIndex(item.FunObj.ParameterDeclarations,item2 => item2.Name==name);
						if (index!=-1)
						{
							info=index;
							return 2;
						}
					}

					if (item.Variables.TryGetValue(name,out info))
						return 3;
				}

				info=((_localsGeneration==LocalsGeneration.Field)&&(!isThis)?_myTypeBldr:_typBldr).DefineField(name,_objectType,FieldAttributes.Public);
				FunctionInfo[] fces=_functions.ToArray();
				FunctionInfo fce=fces[fces.Length-1];
				fce.Variables.Add(name,info);
				if (!isThis)
					fce.ExternalVariables.Add(name);
				return 3;
			}

			void GetVar(ILGenerator gen,BindingWrapper w)
			{
				GetVar(gen,w.Name,w.Context);
			}

			void GetVar(ILGenerator gen,BindingWrapper w,bool isThis)
			{
				GetVar(gen,w.Name,w.Context,isThis);
			}

			void GetVar(ILGenerator gen,string name,Context context)
			{
				GetVar(gen,name,context,false);
			}
			
			void GetVar(ILGenerator gen,string name,Context context,bool isThis)
			{
				object info;
				switch (GetVarType(name,context,isThis,out info))
				{
					case 1:
						gen.Emit(OpCodes.Ldloc,(LocalBuilder)info);
						break;
					case 2:
						gen.Emit(OpCodes.Ldarg,((int)info)+1);
						break;
					case 3:
						EmitFindVarContainer(gen,name,isThis);
						gen.Emit(OpCodes.Ldfld,(FieldBuilder)info);
						break;
				}
				_functions.Peek().Pushes++;
			}

			void PreSetVar(ILGenerator gen,string name,Context context)
			{
				PreSetVar(gen,name,context,false);
			}
			
			void PreSetVar(ILGenerator gen,string name,Context context,bool isThis)
			{
				object info;
				if (GetVarType(name,context,isThis,out info)==3)
					EmitFindVarContainer(gen,name,isThis);
			}

			void EmitFindVarContainer(ILGenerator gen,string name,bool isThis)
			{
				gen.Emit(OpCodes.Ldarg_0);
				if (!isThis)
				{
					gen.Emit(OpCodes.Ldstr,name);
					gen.Emit(OpCodes.Call,GetRuntimeMethod(typeof(FunctionObjectBase).GetMethod("FindVarContainer",BindingFlags.NonPublic|BindingFlags.Instance)));
				}
			}

			void PreSetVar(ILGenerator gen,BindingWrapper w)
			{
				PreSetVar(gen,w.Name,w.Context);
			}

			void PreSetVar(ILGenerator gen,BindingWrapper w,bool isThis)
			{
				PreSetVar(gen,w.Name,w.Context,isThis);
			}

			void SetVar(ILGenerator gen,string name,Context context)
			{
				SetVar(gen,name,context,false);
			}
			
			void SetVar(ILGenerator gen,string name,Context context,bool isThis)
			{
				object info;
				switch (GetVarType(name,context,isThis,out info))
				{
					case 1:
						gen.Emit(OpCodes.Stloc,(LocalBuilder)info);
						break;
					case 2:
						gen.Emit(OpCodes.Starg,((int)info)+1);
						break;
					case 3:
						gen.Emit(OpCodes.Stfld,(FieldBuilder)info);
						break;
				}
				_functions.Peek().Pushes--;
			}

			void SetVar(ILGenerator gen,BindingWrapper w)
			{
				SetVar(gen,w.Name,w.Context);
			}

			void SetVar(ILGenerator gen,BindingWrapper w,bool isThis)
			{
				SetVar(gen,w.Name,w.Context,isThis);
			}

			void FinalizeFunctionPushes(ILGenerator gen,int count)
			{
				for (int a=0;a<count;a++)
					gen.Emit(OpCodes.Pop);
				_functions.Peek().Pushes-=count;
			}
			#endregion get/set vars

			#region helper methods
			void FinalizeFunctionPushes(ILGenerator gen)
			{
				FinalizeFunctionPushes(gen,_functions.Peek().Pushes);
			}

			void MarkSequencePoint(ILGenerator gen,AST node)
			{
				if (!_debug)
					return;
				Context c=AstWrapper.GetContext(node);
				gen.MarkSequencePoint(_symbolWriter,c.StartLine,c.StartColumn+1,c.EndLine,c.EndColumn+1);
			}

			class FunctionInfo
			{
				internal FunctionObjectWrapper FunObj;
				internal Label EndLabel;
				internal LocalBuilder ResultValue;

				internal SortedDictionary<string,object> Variables=new SortedDictionary<string,object>(FunctionObjectBase.VariableNameComparer);
				internal List<string> ExternalVariables=new List<string>();
				internal int Pushes;
				internal Stack<LoopLabels> LoopLabels=new Stack<LoopLabels>();
			}

			class LoopLabels
			{
				internal Label Next;
				internal Label Finish;
			}

			class Point:IComparable<Point>
			{
				internal Point(AST ast)
				{
					Context c=AstWrapper.GetContext(ast);
					EndLine=c.EndLine;
					EndColumn=c.EndColumn;
				}

				internal int EndLine;
				internal int EndColumn;

				public int CompareTo(Point other)
				{
					return EndLine==other.EndLine?EndColumn.CompareTo(other.EndColumn):EndLine.CompareTo(other.EndLine);
				}
			}
			#endregion helper methods
		}
	}

	#region CompilerOptions
	public class CompilerOptions
	{
		public bool Debug {get;set;}
		public RuntimeMethodsUsage RuntimeMethodsUsage {get;set;}
		public LocalsGeneration LocalsGeneration { get; set; }
		public FileKind FileKind {get;set;}
		public string SourceFilename {get;set;}
	}
	#endregion CompilerOptions

	#region CompilerException
	public class CompilerException:Exception
	{
		internal CompilerException(CompilerExceptionReason reason,params object[] data)
		{
			Reason=reason;
			ReasonData=data;
		}

		public CompilerExceptionReason Reason { get; private set; }
		public object[] ReasonData { get; private set; }
	}
	public enum CompilerExceptionReason { InvalidConditionalOperand, UnknownObjectType, InternalErrorCopyRuntime, CantResolveLibrary }
	#endregion CompilerException
}
